﻿using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Pixster.Controllers;

namespace Pixster.Tests.Controllers
{

    [TestClass]
    public class AccountControllerTest
    {
        [TestMethod]
        public void ConstructorSetsProperties()
        {
            IFormsAuthentication formsAuth = new MockFormsAuthenticationService();
            var controller = new AccountController(formsAuth);

            Assert.AreEqual(formsAuth, controller.FormsAuth, "FormsAuth property did not match.");
        }

        [TestMethod]
        public void ConstructorSetsPropertiesToDefaultValues()
        {
            var controller = new AccountController();

            Assert.IsNotNull(controller.FormsAuth, "FormsAuth property is null.");
        }

        [TestMethod]
        public void LoginGet()
        {
            var controller = GetAccountController();
            var result = (ViewResult)controller.LogOn();

            Assert.IsNotNull(result);
        }

        [TestMethod]
        public void LoginPostRedirectsHomeIfLoginSuccessfulButNoReturnUrlGiven()
        {
            var controller = GetAccountController();
            var result = (RedirectToRouteResult)controller.LogOn("someUser", "goodPass", true, null);

            Assert.AreEqual("Home", result.RouteValues["controller"]);
            Assert.AreEqual("Index", result.RouteValues["action"]);
        }

        [TestMethod]
        public void LoginPostRedirectsToReturnUrlIfLoginSuccessfulAndReturnUrlGiven()
        {
            var controller = GetAccountController();
            var result = (RedirectResult)controller.LogOn("someUser", "goodPass", false, "someUrl");

            Assert.AreEqual("someUrl", result.Url);
        }

        [TestMethod]
        public void LoginPostReturnsViewIfPasswordNotSpecified()
        {
            var controller = GetAccountController();
            var result = (ViewResult)controller.LogOn("username", "", true, null);

            Assert.AreEqual("You must specify a password.", result.ViewData.ModelState["password"].Errors[0].ErrorMessage);
        }

        [TestMethod]
        public void LoginPostReturnsViewIfUsernameNotSpecified()
        {
            var controller = GetAccountController();
            var result = (ViewResult)controller.LogOn("", "somePass", false, null);

            Assert.AreEqual("You must specify a username.", result.ViewData.ModelState["username"].Errors[0].ErrorMessage);
        }

        [TestMethod]
        public void LoginPostReturnsViewIfUsernameOrPasswordIsIncorrect()
        {
            var controller = GetAccountController();
            var result = (ViewResult)controller.LogOn("someUser", "badPass", true, null);

            // Assert
            Assert.AreEqual("The username or password provided is incorrect.", result.ViewData.ModelState["_FORM"].Errors[0].ErrorMessage);
        }

        [TestMethod]
        public void LogOff()
        {
            var controller = GetAccountController();
            var result = (RedirectToRouteResult)controller.LogOff();

            Assert.AreEqual("Home", result.RouteValues["controller"]);
            Assert.AreEqual("Index", result.RouteValues["action"]);
        }

        private static AccountController GetAccountController()
        {
            IFormsAuthentication formsAuth = new MockFormsAuthenticationService();
            var controller = new AccountController(formsAuth);
            var controllerContext = new ControllerContext(new MockHttpContext(), new RouteData(), controller);
            controller.ControllerContext = controllerContext;
            return controller;
        }

        public class MockFormsAuthenticationService : IFormsAuthentication
        {
            public void SignIn(string userName, bool createPersistentCookie)
            {
            }

            public void SignOut()
            {
            }
        }

        public class MockIdentity : IIdentity
        {
            public string AuthenticationType
            {
                get { return "MockAuthentication"; }
            }

            public bool IsAuthenticated
            {
                get { return true; }
            }

            public string Name
            {
                get { return "someUser"; }
            }
        }

        public class MockPrincipal : IPrincipal
        {
            IIdentity _identity;

            public IIdentity Identity
            {
                get
                {
                    if (_identity == null)
                    {
                        _identity = new MockIdentity();
                    }
                    return _identity;
                }
            }

            public bool IsInRole(string role)
            {
                return false;
            }
        }

        public class MockMembershipUser : MembershipUser
        {
            public override bool ChangePassword(string oldPassword, string newPassword)
            {
                return newPassword.Equals("newPass");
            }
        }

        public class MockHttpContext : HttpContextBase
        {
            private IPrincipal _user;

            public override IPrincipal User
            {
                get
                {
                    if (_user == null)
                    {
                        _user = new MockPrincipal();
                    }
                    return _user;
                }
                set
                {
                    _user = value;
                }
            }
        }
    }
}